#include "link_manager.h"
#include "ns3/log.h"
#include "ns3/constant-position-mobility-model.h"
#include "ns3/mobility-model.h"
#include "ns3/udp-echo-helper.h"
#include <cmath>
#include <algorithm>

namespace ns3 {

NS_LOG_COMPONENT_DEFINE("LinkManager");

LinkManager::LinkManager() 
  : m_nodeManager(nullptr)
{
  NS_LOG_FUNCTION(this);
}

LinkManager::~LinkManager() 
{
  NS_LOG_FUNCTION(this);
}

bool LinkManager::Initialize(NodeManager& nodeManager) 
{
  NS_LOG_FUNCTION(this);
  
  m_nodeManager = &nodeManager;
  
  // 地址助手将在Reset()方法中初始化
  // 这样可以确保每次模拟使用不同的地址范围
  Reset();
  
  return true;
}

bool LinkManager::SetupWifiConnections() 
{
  NS_LOG_FUNCTION(this);
  
  if (!m_nodeManager) {
    NS_LOG_ERROR("节点管理器未初始化");
    return false;
  }
  
  // 获取车辆节点和地面基站节点
  Ptr<Node> vehicleNode = m_nodeManager->GetVehicleNode();
  NodeContainer groundStations = m_nodeManager->GetGroundStationNodes();
  
  if (!vehicleNode || groundStations.GetN() == 0) {
    NS_LOG_ERROR("车辆节点或地面基站节点未设置");
    return false;
  }
  
  // 创建WiFi助手
  WifiHelper wifi;
  wifi.SetStandard(WIFI_STANDARD_80211n);
  
  // 设置WiFi物理层
  YansWifiPhyHelper wifiPhy;
  YansWifiChannelHelper wifiChannel = YansWifiChannelHelper::Default();
  wifiPhy.SetChannel(wifiChannel.Create());
  
  // 设置覆盖范围为2km
  wifiPhy.Set("TxPowerStart", DoubleValue(30.0));
  wifiPhy.Set("TxPowerEnd", DoubleValue(30.0));
  wifiPhy.Set("TxGain", DoubleValue(12));
  wifiPhy.Set("RxGain", DoubleValue(12));
  
  // 设置WiFi MAC层
  WifiMacHelper wifiMac;
  wifiMac.SetType("ns3::AdhocWifiMac");
  
  // 创建车辆的WiFi设备
  NetDeviceContainer vehicleWifiDevice = wifi.Install(wifiPhy, wifiMac, vehicleNode);
  
  // 为每个地面基站创建WiFi设备
  for (uint32_t i = 0; i < groundStations.GetN(); ++i) {
    Ptr<Node> gsNode = groundStations.Get(i);
    uint32_t gsId = i;
    
    // 创建地面基站的WiFi设备
    NetDeviceContainer gsWifiDevice = wifi.Install(wifiPhy, wifiMac, gsNode);
    
    // 将车辆与地面基站的设备组合
    NetDeviceContainer pairDevices;
    pairDevices.Add(vehicleWifiDevice);
    pairDevices.Add(gsWifiDevice);
    
    // 添加到WiFi设备集合
    m_wifiDevices.Add(pairDevices);
    
    // 计算距离
    double distance = CalculateDistance(vehicleNode, gsNode);
    
    // 添加连接信息
    ConnectionInfo connInfo;
    connInfo.nodeId = gsId;
    connInfo.nodeType = "GroundStation";
    connInfo.distance = distance;
    m_gsConnections[gsId] = connInfo;
    
    NS_LOG_INFO("已设置车辆与地面基站 " << gsId << " 的WiFi连接, 距离: " 
               << distance << " m");
  }
  
  return true;
}

bool LinkManager::SetupSatelliteConnections() 
{
  NS_LOG_FUNCTION(this);
  
  if (!m_nodeManager) {
    NS_LOG_ERROR("节点管理器未初始化");
    return false;
  }
  
  // 获取车辆节点和卫星节点
  Ptr<Node> vehicleNode = m_nodeManager->GetVehicleNode();
  NodeContainer satellites = m_nodeManager->GetSatelliteNodes();
  
  if (!vehicleNode || satellites.GetN() == 0) {
    NS_LOG_ERROR("车辆节点或卫星节点未设置");
    return false;
  }
  
  // 创建P2P助手
  PointToPointHelper p2p;
  
  // 为每个卫星创建P2P连接
  for (uint32_t i = 0; i < satellites.GetN(); ++i) {
    Ptr<Node> satNode = satellites.Get(i);
    uint32_t satId = i;
    
    // 计算距离
    double distance = CalculateDistance(vehicleNode, satNode);
    
    // 根据距离调整链路参数
    double dataRate = 50.0 * 1000 * 1000 / (1 + distance / 1000000); // 根据距离降低速率
    double delay = distance / 299792458.0; // 光速传输延迟
    
    // 设置P2P链路参数
    p2p.SetDeviceAttribute("DataRate", StringValue(std::to_string(dataRate) + "bps"));
    p2p.SetChannelAttribute("Delay", TimeValue(Seconds(delay)));
    
    // 创建设备
    NetDeviceContainer p2pDevices = p2p.Install(vehicleNode, satNode);
    m_p2pDevices[satId] = p2pDevices;
    
    // 添加连接信息
    ConnectionInfo connInfo;
    connInfo.nodeId = satId;
    connInfo.nodeType = "Satellite";
    connInfo.distance = distance;
    m_satelliteConnections[satId] = connInfo;
    
    NS_LOG_INFO("已设置车辆与卫星 " << satId << " 的P2P连接, 距离: " 
               << distance << " m, 延迟: " << delay << " s, 速率: " 
               << dataRate / 1000000 << " Mbps");
  }
  
  return true;
}

bool LinkManager::AssignIpAddresses() 
{
  NS_LOG_FUNCTION(this);
  
  if (!m_nodeManager) {
    NS_LOG_ERROR("节点管理器未初始化");
    return false;
  }
  
  // 分配WiFi连接的IP地址
  for (auto& entry : m_gsConnections) {
    uint32_t gsId = entry.first;
    ConnectionInfo& connInfo = entry.second;
    
    // 从设备集合中获取该基站对应的设备
    NetDeviceContainer devices;
    devices.Add(m_wifiDevices.Get(gsId * 2));
    devices.Add(m_wifiDevices.Get(gsId * 2 + 1));
    
    // 分配IP地址
    connInfo.ipIfaces = m_wifiAddresses.Assign(devices);
    m_wifiAddresses.NewNetwork();
    
    NS_LOG_INFO("已为车辆与地面基站 " << gsId << " 分配IP地址: " 
               << connInfo.ipIfaces.GetAddress(0) << " <-> " 
               << connInfo.ipIfaces.GetAddress(1));
  }
  
  // 分配P2P连接的IP地址
  for (auto& entry : m_satelliteConnections) {
    uint32_t satId = entry.first;
    ConnectionInfo& connInfo = entry.second;
    
    // 获取P2P设备
    NetDeviceContainer& p2pDevices = m_p2pDevices[satId];
    
    // 分配IP地址
    connInfo.ipIfaces = m_p2pAddresses.Assign(p2pDevices);
    m_p2pAddresses.NewNetwork();
    
    NS_LOG_INFO("已为车辆与卫星 " << satId << " 分配IP地址: " 
               << connInfo.ipIfaces.GetAddress(0) << " <-> " 
               << connInfo.ipIfaces.GetAddress(1));
  }
  
  return true;
}

void LinkManager::SetupApplications() 
{
  NS_LOG_FUNCTION(this);
  
  if (!m_nodeManager) {
    NS_LOG_ERROR("节点管理器未初始化");
    return;
  }
  
  // 设置应用服务器端口
  uint16_t port = 9;
  
  // 为每个地面基站设置应用
  for (auto& entry : m_gsConnections) {
    uint32_t gsId = entry.first;
    ConnectionInfo& connInfo = entry.second;
    
    // 创建Echo服务器 (安装在地面基站上)
    UdpEchoServerHelper echoServer(port);
    ApplicationContainer serverApps = echoServer.Install(m_nodeManager->GetGroundStationNode(gsId));
    serverApps.Start(Seconds(1.0));
    serverApps.Stop(Seconds(3600.0));
    
    // 创建Echo客户端 (安装在车辆上)
    UdpEchoClientHelper echoClient(connInfo.ipIfaces.GetAddress(1), port);
    echoClient.SetAttribute("MaxPackets", UintegerValue(10000));
    echoClient.SetAttribute("Interval", TimeValue(Seconds(0.1)));
    echoClient.SetAttribute("PacketSize", UintegerValue(1024));
    
    ApplicationContainer clientApps = echoClient.Install(m_nodeManager->GetVehicleNode());
    clientApps.Start(Seconds(2.0));
    clientApps.Stop(Seconds(3600.0));
    
    // 保存应用
    connInfo.apps.Add(serverApps);
    connInfo.apps.Add(clientApps);
    
    NS_LOG_INFO("已为车辆与地面基站 " << gsId << " 设置UDP Echo应用");
  }
  
  // 为每个卫星设置应用
  for (auto& entry : m_satelliteConnections) {
    uint32_t satId = entry.first;
    ConnectionInfo& connInfo = entry.second;
    
    // 创建Echo服务器 (安装在卫星上)
    UdpEchoServerHelper echoServer(port);
    ApplicationContainer serverApps = echoServer.Install(m_nodeManager->GetSatelliteNode(satId));
    serverApps.Start(Seconds(1.0));
    serverApps.Stop(Seconds(3600.0));
    
    // 创建Echo客户端 (安装在车辆上)
    UdpEchoClientHelper echoClient(connInfo.ipIfaces.GetAddress(1), port);
    echoClient.SetAttribute("MaxPackets", UintegerValue(10000));
    echoClient.SetAttribute("Interval", TimeValue(Seconds(0.2))); // 卫星通信间隔稍大
    echoClient.SetAttribute("PacketSize", UintegerValue(1024));
    
    ApplicationContainer clientApps = echoClient.Install(m_nodeManager->GetVehicleNode());
    clientApps.Start(Seconds(2.0));
    clientApps.Stop(Seconds(3600.0));
    
    // 保存应用
    connInfo.apps.Add(serverApps);
    connInfo.apps.Add(clientApps);
    
    NS_LOG_INFO("已为车辆与卫星 " << satId << " 设置UDP Echo应用");
  }
}

const std::map<uint32_t, ConnectionInfo>& LinkManager::GetGroundStationConnections() const 
{
  return m_gsConnections;
}

const std::map<uint32_t, ConnectionInfo>& LinkManager::GetSatelliteConnections() const 
{
  return m_satelliteConnections;
}

Ptr<Ipv4> LinkManager::GetVehicleIpv4(ConnectionType type, uint32_t nodeId) const 
{
  const ConnectionInfo* connInfo = nullptr;
  
  if (type == ConnectionType::WIFI) {
    auto it = m_gsConnections.find(nodeId);
    if (it != m_gsConnections.end()) {
      connInfo = &(it->second);
    }
  } else if (type == ConnectionType::SATELLITE) {
    auto it = m_satelliteConnections.find(nodeId);
    if (it != m_satelliteConnections.end()) {
      connInfo = &(it->second);
    }
  }
  
  if (connInfo && connInfo->ipIfaces.GetN() > 0) {
    return connInfo->ipIfaces.Get(0).first;
  }
  
  return nullptr;
}

Ptr<Ipv4> LinkManager::GetTargetIpv4(ConnectionType type, uint32_t nodeId) const 
{
  const ConnectionInfo* connInfo = nullptr;
  
  if (type == ConnectionType::WIFI) {
    auto it = m_gsConnections.find(nodeId);
    if (it != m_gsConnections.end()) {
      connInfo = &(it->second);
    }
  } else if (type == ConnectionType::SATELLITE) {
    auto it = m_satelliteConnections.find(nodeId);
    if (it != m_satelliteConnections.end()) {
      connInfo = &(it->second);
    }
  }
  
  if (connInfo && connInfo->ipIfaces.GetN() >= 2) {
    return connInfo->ipIfaces.Get(1).first;
  }
  
  return nullptr;
}

ApplicationContainer LinkManager::GetApplications(ConnectionType type, uint32_t nodeId) const 
{
  ApplicationContainer empty;
  
  if (type == ConnectionType::WIFI) {
    auto it = m_gsConnections.find(nodeId);
    if (it != m_gsConnections.end()) {
      return it->second.apps;
    }
  } else if (type == ConnectionType::SATELLITE) {
    auto it = m_satelliteConnections.find(nodeId);
    if (it != m_satelliteConnections.end()) {
      return it->second.apps;
    }
  }
  
  return empty;
}

double LinkManager::GetDistance(ConnectionType type, uint32_t nodeId) const 
{
  if (type == ConnectionType::WIFI) {
    auto it = m_gsConnections.find(nodeId);
    if (it != m_gsConnections.end()) {
      return it->second.distance;
    }
  } else if (type == ConnectionType::SATELLITE) {
    auto it = m_satelliteConnections.find(nodeId);
    if (it != m_satelliteConnections.end()) {
      return it->second.distance;
    }
  }
  
  return -1.0;
}

void LinkManager::Reset() 
{
  NS_LOG_FUNCTION(this);
  
  m_wifiDevices = NetDeviceContainer();
  m_p2pDevices.clear();
  m_gsConnections.clear();
  m_satelliteConnections.clear();
  
  // 重置IP地址分配
  // 由于NS-3的Ipv4AddressHelper使用静态变量跟踪分配的地址
  // 我们需要使用不同的子网来避免地址冲突
  static uint32_t wifiSubnet = 1;
  static uint32_t p2pSubnet = 1;
  
  // 为每次模拟使用新的子网，使用完全不同的网段
  std::string wifiBase = "10." + std::to_string(wifiSubnet) + ".0.0";
  std::string p2pBase = "172." + std::to_string(p2pSubnet) + ".0.0";  // 使用完全不同的网段
  
  m_wifiAddresses.SetBase(wifiBase.c_str(), "255.255.0.0");
  m_p2pAddresses.SetBase(p2pBase.c_str(), "255.255.0.0");
  
  // 增加子网号，为下一次模拟准备
  wifiSubnet = (wifiSubnet % 90) + 1;  // 使用1-90的子网号
  p2pSubnet = (p2pSubnet % 90) + 1;    // 使用1-90的子网号
  
  NS_LOG_INFO("重置LinkManager完成，新的WiFi基地址: " << wifiBase 
              << ", 新的P2P基地址: " << p2pBase);
}

double LinkManager::CalculateDistance(Ptr<Node> node1, Ptr<Node> node2) const 
{
  if (!node1 || !node2) {
    return -1.0;
  }
  
  Ptr<MobilityModel> mobility1 = node1->GetObject<MobilityModel>();
  Ptr<MobilityModel> mobility2 = node2->GetObject<MobilityModel>();
  
  if (!mobility1 || !mobility2) {
    return -1.0;
  }
  
  Vector pos1 = mobility1->GetPosition();
  Vector pos2 = mobility2->GetPosition();
  
  // 计算欧式距离
  double dx = pos1.x - pos2.x;
  double dy = pos1.y - pos2.y;
  double dz = pos1.z - pos2.z;
  
  return std::sqrt(dx*dx + dy*dy + dz*dz);
}

} // namespace ns3
